import { popTarget, pushTarget } from "./dep";
import { nextTick } from "./next-tick";

let id = 0;
export default class Watcher {
    constructor(vm, expOrFn, cb, options = {}) {
        this.id = id++;
        this.cb = cb;
        this.vm = vm;
        this.depId = new Set();
        // 计算属性使用
        this.lazy = !!options.lazy;
        this.dirty = true;
        this.user = !!options.user;
        // 用户自定义watcher
        this.deps = [];
        if (typeof expOrFn === 'function') {
            this.setter = expOrFn;
        } else { // 用户自定义watch对象的key
            this.setter = () => {
                let token = expOrFn.split('.');
                let value = token.reduce((memo, current) => {
                    return memo[current];
                }, this.vm)
                return value;
            }
        }
        // computed第一次不走，watcher走，得到返回的vm上的值
        this.value = !this.lazy ? this.get() : '';
    }
    get() {
        // 给Dep.target赋值
        pushTarget(this);
        // 拿到计算属性的返回值
        let result = this.setter.call(this.vm);
        // 模板取值完后，将Dep.target清楚掉
        popTarget();
        return result;
    }
    addDep(dep) {
        const id = dep.id;
        if (!this.depId.has(id)) {
            this.depId.add(id);
            this.deps.push(dep);
            dep.addSub(this);
        }
    }
    update() {
        // 重新执行updateComponent, 从新从模板中拿到新值
        // 这里要异步更新
        queue(this);
        // this.run();
    }
    run() {
        // 更新了，就将其置为脏的 计算属性处理
        if (this.lazy) {
            this.dirty = true;
        } else {
            let newValue = this.get(); // 得到新的值
            // 调用watch函数
            if (this.user) {
                let oldVal = this.value;// 老的值
                this.value = newValue;
                this.cb(newValue, oldVal);
            } else {
                this.cb();
            }


        }
    }
    evaluate() {
        // 只有dirty为true，才走到这里
        this.value = this.get();
        this.dirty = false;
    }

    depend() { // 让计算属性watcher存的dep去记住渲染watcher
        for (let i = 0; i < this.deps.length; i++) {
            let dep = this.deps[i];
            dep.depend();
        }
    }
}


// 将watcher去重
const watcherIds = new Set();
// 存放watcher
const callbacks = [];
let pending = false;
function flashCallbacks() {
    callbacks.forEach(watcher => {
        watcher.run();
    })
    pending = false;
    callbacks.length = 0;
}
function queue(watcher) {
    let id = watcher.id;
    if (!watcherIds.has(id)) {
        callbacks.push(watcher);
        watcherIds.add(id);
        if (!pending) {
            // 开始执行更新
            pending = true;
            nextTick(flashCallbacks);
        }
    }
}